#ifndef __SHM_HPP__
#define __SHM_HPP__
#include <iostream>
#include <string>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>


const int creater = 1;
const int user = 0;
const char *pathname = "/home/lazy/linux/lower_code/shm";
const size_t shm_size = 4096;
const int proc_id = 0x66;

class Shm
{
private:
    // 获取到key
    key_t Getkey()
    {
        key_t key = ftok(_pathname.c_str(), _proc_id);
        if (key < 0)
        {
            perror("ftok");
        }
        return key;
    }
    // 获取shmid
    int GetShmid(key_t key, size_t size, int shmflg)
    {
        int shmid = shmget(key, size, shmflg);
        if (shmid < 0)
        {
            perror("shmget");
        }
        return shmid;
    }
    // Creater的封装
    bool GetUserForCreate()
    {
        if (_who == creater)
        {
            _shmid = GetShmid(_key, shm_size, IPC_CREAT | IPC_EXCL | 0666);
            if (_shmid >= 0)
                return true;
        }
        std::cout << "shm fail create..." << std::endl;
        return false;
    }
    // user的封装
    bool GetUserForUser()
    {
        if (_who == user)
        {
            _shmid = GetShmid(_key, shm_size, IPC_CREAT | 0666);
            if (_shmid >= 0)
                return true;
        }
        std::cout << "shm fail create..." << std::endl;
        return false;
    }
    // 将key转换为16进制的
    std::string ToHex(key_t key)
    {
        char buffer[128];
        snprintf(buffer, sizeof(buffer), "0x%x", key);
        return buffer;
    }
    // 获取共享内存的地址
    void *AttachShm()
    {
        if (_addrshm != nullptr)
            DetachShm(_addrshm);
        void *shmaddr = shmat(_shmid, nullptr, 0);
        if (shmaddr == nullptr)
        {
            perror("shmat");
        }
        return shmaddr;
    }
    //脱离
    void DetachShm(void *shmaddr)
    {
        if (shmaddr == nullptr)
            return;
        shmdt(shmaddr);
    }

public:
    Shm(const std::string &pathname, int proc_id, int who)
        : _pathname(pathname), _proc_id(proc_id), _who(who), _addrshm(nullptr)
    {
        _key = Getkey();
        if (_who == creater)
            GetUserForCreate();
        else
            GetUserForUser();
        _addrshm = AttachShm();
    }

    ~Shm()
    {
        if (_who == creater)
        {
            int res = shmctl(_shmid, IPC_RMID, nullptr);
        }
        std::cout << "shm remove done..." << std::endl;
    }
    //给地址
    void *Addr()
    {
        return _addrshm;
    }
    //初识化共享内存的空间
    void Zero()
    {
        if (_addrshm)
        {
            memset(_addrshm, 0, shm_size);
        }
    }
private:
    key_t _key;
    int _shmid;

    int _who;

    std::string _pathname;
    int _proc_id;
    void *_addrshm;
};

#endif